/**
 * 
 */
package org.hackystat.projecttrajectory.db;

import static org.junit.Assert.*;
import java.math.BigInteger;
import javax.xml.bind.JAXBException;
import org.hackystat.project.ProjectException;
import org.hackystat.projecttrajectory.ProjectTrajectoryProperties;
import org.hackystat.projecttrajectory.resource.ResourceFactory;
import org.hackystat.projecttrajectory.resource.estimate.jaxb.EstimateData;
import org.hackystat.projecttrajectory.resource.estimate.jaxb.EstimateIndex;
import org.hackystat.projecttrajectory.resource.estimate.jaxb.ProjectEstimate;
import org.hackystat.projecttrajectory.test.ProjectTrajectoryTestHelper;
import org.hackystat.sensorbase.client.SensorBaseClient;
import org.hackystat.sensorbase.client.SensorBaseClientException;
import org.hackystat.sensorbase.resource.projects.jaxb.Project;
import org.hackystat.sensorbase.resource.users.jaxb.User;
import org.hackystat.utilities.stacktrace.StackTrace;
import org.hackystat.utilities.tstamp.Tstamp;
import org.junit.BeforeClass;
import org.junit.Test;

/**
 * Test cases for the DbManager.
 * @author Cam Moore
 *
 */
public class TestDbManager {

  private static final String user = "TestEstimate@hackystat.org";
  private static final String error = "Error: ";
  private static final String projectName = "Default";
  private static final String nullManager = "Got null dbManager";
  
  /**
   * Sets up the test sensorbase, dailyprojectdata, and projecttrajectory 
   * servers.
   * @throws Exception if there is a problem.
   */
  @BeforeClass
  public static void setUpBeforeClass() throws Exception {
    ProjectTrajectoryProperties properties = ProjectTrajectoryProperties.getInstance();
    properties.setTestProperties();
    ProjectTrajectoryTestHelper.setupServer();
  }

  /**
   * Test method for 
   * {@link org.hackystat.projecttrajectory.db.DbManager#DbManager(
   * org.hackystat.projecttrajectory.server.Server)}.
   */
  @Test
  public void testDbManager() {
    try {
      ResourceFactory factory = ResourceFactory.getInstance();
      DbManager manager = new DbManager(ProjectTrajectoryTestHelper.getProjectTrajectoryServer());
      assertNotNull(nullManager, manager);
      String allProjectsIndex = manager.getProjectEstimateIndex();
      assertFalse("Got empty project index", "".equals(allProjectsIndex));
      EstimateIndex index = factory.makeEstimateIndex(allProjectsIndex);
      assertNotNull("Failed to convert project index String", index);
      String defaultProjectIndex = manager.getProjectEstimateIndex(projectName);
      assertFalse("Got empty index for Default", "".equals(defaultProjectIndex));
      index = factory.makeEstimateIndex(defaultProjectIndex);
      assertNotNull("Failed to convert default project index String", index);
      String testUserIndex = manager.getUserEstimateIndex("TestEstimate@hackystat.org");
      assertFalse("Got empty index for TestEstimate", "".equals(testUserIndex));
      index = factory.makeEstimateIndex(testUserIndex);
      assertNotNull("Failed to convert test user index String", index);
    } catch (JAXBException e) {
      fail(error + StackTrace.toString(e));
    }
  }

  /**
   * Test method for 
   * {@link org.hackystat.projecttrajectory.db.DbManager#storeProjectEstimate(
   * org.hackystat.projecttrajectory.resource.estimate.jaxb.ProjectEstimate, 
   * java.lang.String, java.lang.String)}.
   */
  @Test
  public void testStoreProjectEstimate() {
    try {
      ResourceFactory factory = ResourceFactory.getInstance();
      DbManager manager = new DbManager(ProjectTrajectoryTestHelper.getProjectTrajectoryServer());
      assertNotNull(nullManager, manager);
      ProjectEstimate estimate = createTestEstimate();
      String xmlEstimate = factory.makeXml(estimate);
      manager.storeProjectEstimate(estimate, xmlEstimate, xmlEstimate); // wrong ref
      String storedXML = manager.getProjectEstimate(estimate.getEstimator(), estimate.getProject());
      assertFalse("Failed to retrieve stored estimate", "".equals(storedXML));
      ProjectEstimate stored = factory.makeProjectEstimate(storedXML);
      assertNotNull("Could not build stored xml", stored);
      assertEquals("Wrong estimator", estimate.getEstimator(), stored.getEstimator());
      assertEquals("Wrong project", estimate.getProject(), stored.getProject());
      assertSame("Wrong number of data", estimate.getEstimateData().size(), 
          stored.getEstimateData().size());
    } catch (JAXBException e) {
      fail(error + StackTrace.toString(e));
    } catch (Exception e) {
      fail(error + StackTrace.toString(e));
    }
  }
  /**
   * Test method for DbManager.getEstimateIndex(Project).
   */
  @Test
  public void testGetEstimateIndexProject() {
    try {
      ResourceFactory factory = ResourceFactory.getInstance();
      DbManager manager = new DbManager(ProjectTrajectoryTestHelper.getProjectTrajectoryServer());
      assertNotNull(nullManager, manager);
      ProjectTrajectoryProperties properties;
      properties = ProjectTrajectoryProperties.getInstance();
      SensorBaseClient sbClient = new SensorBaseClient(properties.getSensorbase(), user, user);
      SensorBaseClient.registerUser(properties.getSensorbase(), user);
      Project p = sbClient.getProject(user, projectName);
      String xml = manager.getProjectEstimateIndex(p);
      assertFalse("Got null estimate string", "".equals(xml));
      EstimateIndex index = factory.makeEstimateIndex(xml);
      assertNotNull("Failed to convert project index String", index);
//      assertTrue("Default has an estimate", manager.hasProjectEstimate(p));
    } catch (ProjectException e) {
      fail(error + StackTrace.toString(e));
    } catch (SensorBaseClientException e) {
      fail(error + StackTrace.toString(e));
    } catch (JAXBException e) {
      fail(error + StackTrace.toString(e));
    }
  }

  /**
   * Test method for 
   * {@link org.hackystat.projecttrajectory.db.DbManager#getEstimateIndex(
   * org.hackystat.sensorbase.resource.users.jaxb.User)}.
   */
  @Test
  public void testGetEstimateIndexUser() {
    try {
      ResourceFactory factory = ResourceFactory.getInstance();
      DbManager manager = new DbManager(ProjectTrajectoryTestHelper.getProjectTrajectoryServer());
      assertNotNull(nullManager, manager);
      String xml = manager.getUserEstimateIndex(user);
      assertFalse("Got null user index", "".equals(xml));
      EstimateIndex index = factory.makeEstimateIndex(xml);
      assertNotNull("Failed to convert user index String", index);
      ProjectTrajectoryProperties properties;
      properties = ProjectTrajectoryProperties.getInstance();
      SensorBaseClient sbClient = new SensorBaseClient(properties.getSensorbase(), user, user);
      User u = sbClient.getUser(user);
      xml = manager.getEstimateIndex(u);
      assertFalse("Got empty user index", "".equals(xml));
    } catch (JAXBException e) {
      fail(error + StackTrace.toString(e));
    } catch (ProjectException e) {
      fail(error + StackTrace.toString(e));
    } catch (SensorBaseClientException e) {
      fail(error + StackTrace.toString(e));
    }
  }

  /**
   * Test method for 
   * {@link org.hackystat.projecttrajectory.db.DbManager#getProjectEstimate(
   * org.hackystat.sensorbase.resource.users.jaxb.User, 
   * org.hackystat.sensorbase.resource.projects.jaxb.Project)}.
   */
  @Test
  public void testGetProjectEstimateUserProject() {
    try {
      ResourceFactory factory = ResourceFactory.getInstance();
      DbManager manager = new DbManager(ProjectTrajectoryTestHelper.getProjectTrajectoryServer());
      assertNotNull(nullManager, manager);
      ProjectEstimate estimate = createDefaultTestEstimate();
      String storedXML = manager.getProjectEstimate(estimate.getEstimator(), estimate.getProject());
      if (storedXML == null || storedXML.equals("")) { // store the project we are going to delete.
        String xmlEstimate = factory.makeXml(estimate);
        manager.storeProjectEstimate(estimate, xmlEstimate, xmlEstimate); // wrong ref
//        String xml = manager.getProjectEstimate(estimate.getEstimator(), estimate.getProject());
//        System.out.println("Added " + xml);
      }
      ProjectTrajectoryProperties properties;
      properties = ProjectTrajectoryProperties.getInstance();
      SensorBaseClient sbClient = new SensorBaseClient(properties.getSensorbase(), user, user);
      Project p = sbClient.getProject(user, projectName);
      User u = sbClient.getUser(user);
      String xml = manager.getProjectEstimate(u, p);
      assertFalse("Got empty estimate string", "".equals(xml));
      System.out.println(xml);
      try {
      	estimate = factory.makeProjectEstimate(xml);
        assertNotNull("Failed to convert project estimate String", estimate);
        xml = manager.getProjectEstimate(user, projectName);
        assertFalse("Got empty estimate string", "".equals(xml));
        estimate = factory.makeProjectEstimate(xml);
        assertNotNull("Failed to convert project estimate String", estimate);
      } catch (JAXBException e) {
      	manager.deleteProjectEstimate(estimate.getEstimator(), estimate.getProject());
      }
    } catch (ProjectException e) {
      fail(error + StackTrace.toString(e));
    } catch (SensorBaseClientException e) {
      fail(error + StackTrace.toString(e));
    } catch (JAXBException e) {
      fail(error + StackTrace.toString(e));
    }
		catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
  }

  /**
   * Test method for 
   * {@link org.hackystat.projecttrajectory.db.DbManager#hasProjectEstimate(
   * org.hackystat.sensorbase.resource.projects.jaxb.Project, 
   * javax.xml.datatype.XMLGregorianCalendar)}.
   */
  @Test
  public void testHasProjectEstimateProjectXMLGregorianCalendar() {
    try {
      DbManager manager = new DbManager(ProjectTrajectoryTestHelper.getProjectTrajectoryServer());
      assertNotNull(nullManager, manager);
      ProjectTrajectoryProperties properties;
      properties = ProjectTrajectoryProperties.getInstance();
      SensorBaseClient sbClient = new SensorBaseClient(properties.getSensorbase(), user, user);
      Project p = sbClient.getProject(user, projectName);
      assertFalse("There shouldn't be an estimate", 
          manager.hasProjectEstimate(p, Tstamp.makeTimestamp()));
    } catch (ProjectException e) {
      fail(error + StackTrace.toString(e));
    } catch (SensorBaseClientException e) {
      fail(error + StackTrace.toString(e));
    }
  }



  /**
   * Test method for 
   * {@link org.hackystat.projecttrajectory.db.DbManager#deleteProjectEstimate(
   * org.hackystat.sensorbase.resource.projects.jaxb.Project, 
   * javax.xml.datatype.XMLGregorianCalendar)}.
   */
  @Test
  public void testDeleteProjectEstimate() {
    try {
      ResourceFactory factory = ResourceFactory.getInstance();
      DbManager manager = new DbManager(ProjectTrajectoryTestHelper.getProjectTrajectoryServer());
      assertNotNull(nullManager, manager);
      ProjectEstimate estimate = createTestEstimate();
      String storedXML = manager.getProjectEstimate(estimate.getEstimator(), estimate.getProject());
      if (storedXML == null) { // store the project we are going to delete.
        String xmlEstimate = factory.makeXml(estimate);
        manager.storeProjectEstimate(estimate, xmlEstimate, xmlEstimate); // wrong ref
      }
      manager.deleteProjectEstimate(estimate.getEstimator(), estimate.getProject());
      storedXML = manager.getProjectEstimate(estimate.getEstimator(), estimate.getProject());
      assertTrue("xml should be empty", "".equals(storedXML));
    } catch (JAXBException e) {
      fail(error + StackTrace.toString(e));
    } catch (Exception e) {
      fail(error + StackTrace.toString(e));
    }
  }

  /**
   * @return A test ProjectEstimate.
   */
  private ProjectEstimate createTestEstimate() {
    ProjectEstimate estimate = new ProjectEstimate();
    estimate.setEstimator("DeleteMe@hackystat.org");
    estimate.setProject("DeleteMe");
    try {
      estimate.setLastModDate(Tstamp.makeTimestamp("2008-01-01"));
    } catch (Exception e) {
      e.printStackTrace();
      estimate.setLastModDate(Tstamp.makeTimestamp());
    }
    EstimateData data = new EstimateData();
    data.setActiveDays(BigInteger.TEN);
    data.setTotalEffort(BigInteger.valueOf(100));
    data.setTotalSize(BigInteger.ONE);
    try {
      data.setEstimateDate(Tstamp.makeTimestamp("2007-10-10"));
    } catch (Exception e) {
      e.printStackTrace();
    }
    estimate.getEstimateData().add(data);
    return estimate;
  }
  
  /**
   * @return A test ProjectEstimate.
   */
  private ProjectEstimate createDefaultTestEstimate() {
    ProjectEstimate estimate = new ProjectEstimate();
    estimate.setEstimator(user);
    estimate.setProject("Default");
    try {
      estimate.setLastModDate(Tstamp.makeTimestamp("2008-01-01"));
    } catch (Exception e) {
      e.printStackTrace();
      estimate.setLastModDate(Tstamp.makeTimestamp());
    }
    EstimateData data = new EstimateData();
    data.setActiveDays(BigInteger.TEN);
    data.setTotalEffort(BigInteger.valueOf(100));
    data.setTotalSize(BigInteger.ONE);
    try {
      data.setEstimateDate(Tstamp.makeTimestamp("2007-10-10"));
    } catch (Exception e) {
      e.printStackTrace();
    }
    estimate.getEstimateData().add(data);
    return estimate;
  }
}
